package main.scala

/**
 * Rewrite a parser AST to the internal representation
 * used for algebraic transformations.
 * 
 * This introduces new ("synthetic") nodes into the AST,
 * that are not produced by the parser.
 */
object AlgebraicRewriter {

	import main.scala.AST._
	import org.kiama.rewriting.Rewriter._
	
	/**
	 * Rewrite additions to a summation of terms.
	 */
	val sum = rule {
	  case BAdd(Add(tl),Add(tr)) =>
	      Add(tl ++ tr)
	  case BAdd(Add(tl), r) =>
	      Add(r :: tl) // assume symmetry
	  case BAdd(l, Add(tr)) =>
	      Add(l :: tr)
	  case BAdd(l, r) =>
	      Add(List(l, r))
	}
	
	/**
	 * Rewrite subtractions as addition to a negative term.
	 */
	val sub = rule {
	  case BSub(l, r) => 
	    BAdd(l, Neg(r))
	}
	
	/**
	 * Rewrite multiplications as product of terms.
	 */
	val product = rule {
	  case BMul(Mul(tl), Mul(tr)) =>
	    	Mul(tl ++ tr)
	  case BMul(Mul(tl), r) =>
	    	Mul(r :: tl) // assume symmetry
	  case BMul(l, Mul(tr)) =>
	    	Mul(l :: tr)
	  case BMul(l, r) =>
	    	Mul(List(l, r))
	}
	
	/**
	 * Rewrite division as multiplication by the inverse.
	 */
	val division = rule {
	  case BDiv(l, r) => BMul(l, Pow(r, NumI(-1)))
	}
	
	/**
	 * Entry point for rewriting an AST (generated by the parser)
	 * to an AlgebraicAST.
	 */
	def start(e : Exp) : Exp = {
	  rewrite(reduce(sub + division + sum + product))(e)
	}
}